package org.java.order.conf;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

/**
 * @author WHQ
 * @version 1.0
 * @date 2022-3-18 0018 上午 9:38
 */
@Configuration
public class RabbitMqConfig {

    /**
     * 死信交换机
     */
    public static final String DLX_EXCHANGE="shopping_dlx_exchange";
    /**
     * 死信队列
     */
    public static final String DLX_QUEUE="shopping_dlx_queue";
    /**
     * 死信交换机路由key
     */
    public static final String DLX_EXCHANGE_ROUTING_KEY="dlx.order";

    public static final String DLX_ROUTING_KEY="dlx.#";
    /**
     * TTL交换机
     */
    public static final String TTL_EXCHANGE="shopping_ttl_exchange";
    /**
     * TTL队列
     */
    public static final String TTL_QUEUE="shopping_ttl_queue";
    /**
     * TTL队列的路由key
     */
    public static final String TTL_ROUTING_KEY="order.ttl.#";
    /**
     * 购物车队列
     */
    public static final String CART_QUEUE="shopping_cart_queue";
    /**
     * 购物车交换机
     */
    public static final String CART_EXCHANGE="shopping_cart_exchange";
    /**
     * 购物车路由key
     */
    public static final String CART_ROUTING_KEY="shopping.cart.#";
    /*******************************延迟队列之优化队列-开始代码***************************************/
    /***************************************
     * 这个方式还是有缺点，由于消息队列是按照先进先出的方式，
     * 一旦发出两条消息，第一条消息时间比第二条长，理论上应该第二条先到死信队列，
     * 实则rabbitMq只会检查第一个消息是否过期，
     * 如果过期则丢到死信队列， 如果第一个消息的延时时长很长，
     * 而第二个消息的延时时长很短，第二个消息并不会优先得到执行。
     * *****************************************************/
    /**
     * 创建一个普通队列，不设置过期时间，绑定死信队列
     * 过期时间由生产者设定，这样可以大大扩展延迟队列的可用性，灵活性
     */
//    public static final String TTL_DONT_DATE_QUEUE="ttl_dont_date_queue";
    /**
     * 声明不过期ttl的交换机
     */
//    public static final String TTL_DONT_DATE_EXCHANGE="ttl_dont_date_exchange";
    /**
     * 声明路由key
     */
//    public static final String TTL_DONT_DATE_QUEUE_ROUTING_KEY="ttl.dont.date.order.#";
    /**
     * 创建不过期ttl交换机
     */
//    @Bean
//    public Exchange dontDateExchange(){
////        new CustomExchange()
//
//        return ExchangeBuilder.topicExchange(TTL_DONT_DATE_EXCHANGE).durable(true).build();
//    }
//    /**
//     * 创建不过期的ttl队列
//     */
//    @Bean
//    public Queue dontDateQueue(){
//        return QueueBuilder.durable(TTL_DONT_DATE_QUEUE)
//                //绑定死信交换机
//                .deadLetterExchange(DLX_EXCHANGE)
//                //绑定死信交换机的路由key
//                .deadLetterRoutingKey(DLX_EXCHANGE_ROUTING_KEY)
//                .build();
//    }
    /**
     * 将队列与交换机绑定
     */
//    @Bean
//    public Binding dontDateBinding(@Qualifier("dontDateQueue")Queue queue,
//                                   @Qualifier("dontDateExchange")Exchange exchange){
//        return BindingBuilder.bind(queue).to(exchange).with(TTL_DONT_DATE_QUEUE_ROUTING_KEY)
//                .noargs();
//    }
    /**************************************延迟队列之优化队列-结束代码***************************************************/
    /************************开始基于rabbitMq插件实现延迟队列**********************************/
    /**
     * 声明延迟队列名称
     */
    public static final String DELAYED_QUEUE_NAME="delayed_queue";
    /**
     * /声明延迟交换机名称
     */
    public static final String DELAYED_EXCHANGE_NAME="delayed_exchange";
    /**
     * 声明延迟队列的routingKey
     */
    public static final String DELAYED_ROUTING_KEY="delayed.order";

    /**
     * 基于插件声明一个自定义交换机，因为我们使用的交换机是rabbitMq提供的，所以需要自定义
     * @return
     */
    @Bean("delayedExchange")
    public CustomExchange delayedExchange(){
        Map<String, Object> arguments=new HashMap<>();
        arguments.put("x-delayed-type","direct");
        /**
         * 1.交换机的名称
         * 2.交换机的类型
         * 3.是否持久化
         * 4.是否需要自动删除
         * 5.其他参数
         */
        return new CustomExchange(DELAYED_EXCHANGE_NAME,
                "x-delayed-message",true,
                false,arguments);
    }
    /**
     * 声明延迟队列
     * @return
     */
    @Bean("delayedQueue")
    public Queue delayedQueue(){
        return QueueBuilder.durable(DELAYED_QUEUE_NAME).build();
    }
    /**
     * 绑定延迟交换机与延迟队列
     */
    @Bean
    public Binding delayedBinding(@Qualifier("delayedQueue")Queue queue,
                                  @Qualifier("delayedExchange") CustomExchange customExchange){
        return BindingBuilder.bind(queue).to(customExchange).with(DELAYED_ROUTING_KEY).noargs();
    }
    /************************结束基于rabbitMq插件实现延迟队列**********************************/

    /**
     * 声明购物车交换机
     * @return
     */
    @Bean
    public Exchange cartExchange(){
        return ExchangeBuilder.topicExchange(CART_EXCHANGE).durable(true).build();
    }

    /**
     * 声明购物车队列
     * @return
     */
    @Bean
    public Queue cartQueue(){
        return QueueBuilder.
                //绑定队列名称
                durable(CART_QUEUE)
                .build();
    }

    /**
     * 将购物车队列绑定到购物车交换机
     * @param queue
     * @param exchange
     * @return
     */
    @Bean
    public Binding cartBinding(@Qualifier("cartQueue")Queue queue,
                               @Qualifier("cartExchange")Exchange exchange){
        return BindingBuilder.bind(queue).to(exchange).with(CART_ROUTING_KEY).noargs();
    }
    /**
     * 声明TTL交换机
     * @return
     */
    @Bean
    public Exchange ttlExchange(){
        //交换机要用交换机构建类创建出来,构建类有方法指定创建什么类型的交换机,
        // .durable(true)表示交换机用完以后不删除，.build就是创建交换机
        return ExchangeBuilder.topicExchange(TTL_EXCHANGE).durable(true).build();
    }

    /**
     * 声明ttl队列，同时绑定死信交换机
     * @return
     */
    @Bean
    public Queue ttlQueue(){
       return QueueBuilder.
                //绑定队列名称
                durable(TTL_QUEUE).
                //声明队列过期的时间,单位毫秒
                ttl(600000)
                //绑定死信交换机
                .deadLetterExchange(DLX_EXCHANGE)
                //设置死信交换机routingkey
                .deadLetterRoutingKey(DLX_EXCHANGE_ROUTING_KEY)
                //设置队列最大数，可不设置
//                .maxLength(10)
                .build();
    }

    /**
     * 声明死信交换机
     * @return
     */
    @Bean
    public Exchange dlxExchange(){
        return ExchangeBuilder.topicExchange(DLX_EXCHANGE).durable(true).build();
    }

    /**
     * 声明死信队列
     * @return
     */
    @Bean
    public Queue dlxQueue(){
        return QueueBuilder.durable(DLX_QUEUE).build();
    }

    /**
     * 将ttl队列绑定到ttl交换机
     * @param queue
     * @param exchange
     * @return
     */
    @Bean
    public Binding bindingTtl(@Qualifier("ttlQueue")Queue queue,
                              @Qualifier("ttlExchange")Exchange exchange){
        //创建绑定对象
        ////////////////////////////////////绑定哪个队列//在哪个交换机上///交换机的路由key
            return BindingBuilder.bind(queue).to(exchange).with(TTL_ROUTING_KEY).noargs();
    }

    /**
     * 将死信队列绑定到死信交换机
     * @param queue
     * @param exchange
     * @return
     */
    @Bean
    public Binding bindingDlx(@Qualifier("dlxQueue")Queue queue,
                              @Qualifier("dlxExchange")Exchange exchange){
            return BindingBuilder.bind(queue).to(exchange).with(DLX_ROUTING_KEY).noargs();
    }
}
